home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 27 / CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso / CUCD / Programming / Mesa / src-glu / mipmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-02  |  17.7 KB  |  730 lines

  1. /* $Id: mipmap.c,v 1.5 1997/07/24 01:28:44 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.4
  6.  * Copyright (C) 1995-1997  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * mipmap.c
  26.  *
  27.  * Version 1.0  27 Jun 1998
  28.  * by Jarno van der Linden
  29.  * jarno@kcbbs.gen.nz
  30.  *
  31.  * File created from mipmap.c ver 1.5 and glu.h ver 1.9 using GenProtos
  32.  *
  33.  */
  34.  
  35.  
  36. #ifdef PC_HEADER
  37. #include "all.h"
  38. #else
  39. #include <assert.h>
  40. #include <math.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include "gluP.h"
  44. #endif
  45.  
  46.  
  47. /*
  48.  * Compute ceiling of integer quotient of A divided by B:
  49.  */
  50. #define CEILING( A, B )  ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
  51.  
  52.  
  53.  
  54. #ifdef EPSILON
  55. #undef EPSILON
  56. #endif
  57. #define EPSILON 0.001
  58.  
  59.  
  60. /* To work around optimizer bug in MSVC4.1 */
  61. #ifdef __WIN32__
  62. void dummy(GLuint j, GLuint k){
  63. }
  64. #else
  65. #define dummy(J, K)
  66. #endif
  67.  
  68.  
  69. __asm __saveds GLint APIENTRY gluScaleImage( register __d0 GLenum format,
  70.                                              register __d1 GLint widthin, register __d2 GLint heightin,
  71.                                              register __d3 GLenum typein, register __a0 const void *datain,
  72.                                              register __d4 GLint widthout, register __d5 GLint heightout,
  73.                                              register __d6 GLenum typeout, register __a1 void *dataout )
  74. {
  75.    GLint components, i, j, k;
  76.    GLfloat *tempin, *tempout;
  77.    GLfloat sx, sy;
  78.    GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
  79.    GLint packrowlength, packalignment, packskiprows, packskippixels;
  80.    GLint sizein, sizeout;
  81.    GLint rowstride, rowlen;
  82.  
  83.  
  84.    /* Determine number of components per pixel */
  85.    switch (format) {
  86.       case GL_COLOR_INDEX:
  87.       case GL_STENCIL_INDEX:
  88.       case GL_DEPTH_COMPONENT:
  89.       case GL_RED:
  90.       case GL_GREEN:
  91.       case GL_BLUE:
  92.       case GL_ALPHA:
  93.       case GL_LUMINANCE:
  94.          components = 1;
  95.      break;
  96.       case GL_LUMINANCE_ALPHA:
  97.      components = 2;
  98.      break;
  99.       case GL_RGB:
  100.      components = 3;
  101.      break;
  102.       case GL_RGBA:
  103.      components = 4;
  104.      break;
  105.       default:
  106.      return GLU_INVALID_ENUM;
  107.    }
  108.  
  109.    /* Determine bytes per input datum */
  110.    switch (typein) {
  111.       case GL_UNSIGNED_BYTE:    sizein = sizeof(GLubyte);    break;
  112.       case GL_BYTE:        sizein = sizeof(GLbyte);    break;
  113.       case GL_UNSIGNED_SHORT:    sizein = sizeof(GLushort);    break;
  114.       case GL_SHORT:        sizein = sizeof(GLshort);    break;
  115.       case GL_UNSIGNED_INT:    sizein = sizeof(GLuint);    break;
  116.       case GL_INT:        sizein = sizeof(GLint);        break;
  117.       case GL_FLOAT:        sizein = sizeof(GLfloat);    break;
  118.       case GL_BITMAP:
  119.      /* not implemented yet */
  120.       default:
  121.      return GL_INVALID_ENUM;
  122.    }
  123.  
  124.    /* Determine bytes per output datum */
  125.    switch (typeout) {
  126.       case GL_UNSIGNED_BYTE:    sizeout = sizeof(GLubyte);    break;
  127.       case GL_BYTE:        sizeout = sizeof(GLbyte);    break;
  128.       case GL_UNSIGNED_SHORT:    sizeout = sizeof(GLushort);    break;
  129.       case GL_SHORT:        sizeout = sizeof(GLshort);    break;
  130.       case GL_UNSIGNED_INT:    sizeout = sizeof(GLuint);    break;
  131.       case GL_INT:        sizeout = sizeof(GLint);    break;
  132.       case GL_FLOAT:        sizeout = sizeof(GLfloat);    break;
  133.       case GL_BITMAP:
  134.      /* not implemented yet */
  135.       default:
  136.      return GL_INVALID_ENUM;
  137.    }
  138.  
  139.    /* Get glPixelStore state */
  140.    glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
  141.    glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
  142.    glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
  143.    glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
  144.    glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
  145.    glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
  146.    glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
  147.    glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
  148.  
  149.    /* Allocate storage for intermediate images */
  150.    tempin = (GLfloat *) malloc( widthin * heightin
  151.                     * components * sizeof(GLfloat) );
  152.    if (!tempin) {
  153.       return GLU_OUT_OF_MEMORY;
  154.    }
  155.    tempout = (GLfloat *) malloc( widthout * heightout
  156.                       * components * sizeof(GLfloat) );
  157.    if (!tempout) {
  158.       free( tempin );
  159.       return GLU_OUT_OF_MEMORY;
  160.    }
  161.  
  162.  
  163.    /*
  164.     * Unpack the pixel data and convert to floating point
  165.     */
  166.  
  167.    if (unpackrowlength>0) {
  168.       rowlen = unpackrowlength;
  169.    }
  170.    else {
  171.       rowlen = widthin;
  172.    }
  173.    if (sizein >= unpackalignment) {
  174.       rowstride = components * rowlen;
  175.    }
  176.    else {
  177.       rowstride = unpackalignment/sizein
  178.             * CEILING( components * rowlen * sizein, unpackalignment );
  179.    }
  180.  
  181.    switch (typein) {
  182.       case GL_UNSIGNED_BYTE:
  183.      k = 0;
  184.      for (i=0;i<heightin;i++) {
  185.         GLubyte *ubptr = (GLubyte *) datain
  186.                        + i * rowstride
  187.                + unpackskiprows * rowstride
  188.                + unpackskippixels * components;
  189.         for (j=0;j<widthin*components;j++) {
  190.                dummy(j, k);
  191.            tempin[k++] = (GLfloat) *ubptr++;
  192.         }
  193.      }
  194.      break;
  195.       case GL_BYTE:
  196.      k = 0;
  197.      for (i=0;i<heightin;i++) {
  198.         GLbyte *bptr = (GLbyte *) datain
  199.                      + i * rowstride
  200.              + unpackskiprows * rowstride
  201.              + unpackskippixels * components;
  202.         for (j=0;j<widthin*components;j++) {
  203.                dummy(j, k);
  204.            tempin[k++] = (GLfloat) *bptr++;
  205.         }
  206.      }
  207.      break;
  208.       case GL_UNSIGNED_SHORT:
  209.      k = 0;
  210.      for (i=0;i<heightin;i++) {
  211.         GLushort *usptr = (GLushort *) datain
  212.                         + i * rowstride
  213.                 + unpackskiprows * rowstride
  214.                 + unpackskippixels * components;
  215.         for (j=0;j<widthin*components;j++) {
  216.                dummy(j, k);
  217.            tempin[k++] = (GLfloat) *usptr++;
  218.         }
  219.      }
  220.      break;
  221.       case GL_SHORT:
  222.      k = 0;
  223.      for (i=0;i<heightin;i++) {
  224.         GLshort *sptr = (GLshort *) datain
  225.                       + i * rowstride
  226.               + unpackskiprows * rowstride
  227.               + unpackskippixels * components;
  228.         for (j=0;j<widthin*components;j++) {
  229.                dummy(j, k);
  230.            tempin[k++] = (GLfloat) *sptr++;
  231.         }
  232.      }
  233.      break;
  234.       case GL_UNSIGNED_INT:
  235.      k = 0;
  236.      for (i=0;i<heightin;i++) {
  237.         GLuint *uiptr = (GLuint *) datain
  238.                       + i * rowstride
  239.               + unpackskiprows * rowstride
  240.               + unpackskippixels * components;
  241.         for (j=0;j<widthin*components;j++) {
  242.                dummy(j, k);
  243.            tempin[k++] = (GLfloat) *uiptr++;
  244.         }
  245.      }
  246.      break;
  247.       case GL_INT:
  248.      k = 0;
  249.      for (i=0;i<heightin;i++) {
  250.         GLint *iptr = (GLint *) datain
  251.                     + i * rowstride
  252.             + unpackskiprows * rowstride
  253.             + unpackskippixels * components;
  254.         for (j=0;j<widthin*components;j++) {
  255.                dummy(j, k);
  256.            tempin[k++] = (GLfloat) *iptr++;
  257.         }
  258.      }
  259.      break;
  260.       case GL_FLOAT:
  261.      k = 0;
  262.      for (i=0;i<heightin;i++) {
  263.         GLfloat *fptr = (GLfloat *) datain
  264.                       + i * rowstride
  265.               + unpackskiprows * rowstride
  266.               + unpackskippixels * components;
  267.         for (j=0;j<widthin*components;j++) {
  268.                dummy(j, k);
  269.            tempin[k++] = *fptr++;
  270.         }
  271.      }
  272.      break;
  273.       default:
  274.      return GLU_INVALID_ENUM;
  275.    }
  276.  
  277.  
  278.    /*
  279.     * Scale the image!
  280.     */
  281.  
  282.    sx = (GLfloat) widthin / (GLfloat) widthout;
  283.    sy = (GLfloat) heightin / (GLfloat) heightout;
  284.  
  285. /*#define POINT_SAMPLE*/
  286. #ifdef POINT_SAMPLE
  287.    for (i=0;i<heightout;i++) {
  288.       GLint ii = i * sy;
  289.       for (j=0;j<widthout;j++) {
  290.      GLint jj = j * sx;
  291.  
  292.      GLfloat *src = tempin + (ii * widthin + jj) * components;
  293.      GLfloat *dst = tempout + (i * widthout + j) * components;
  294.  
  295.      for (k=0;k<components;k++) {
  296.         *dst++ = *src++;
  297.      }
  298.       }
  299.    }
  300. #else
  301.    if (sx<1.0 && sy<1.0) {
  302.       /* magnify both width and height:  use weighted sample of 4 pixels */
  303.       GLint i0, i1, j0, j1;
  304.       GLfloat alpha, beta;
  305.       GLfloat *src00, *src01, *src10, *src11;
  306.       GLfloat s1, s2;
  307.       GLfloat *dst;
  308.  
  309.       for (i=0;i<heightout;i++) {
  310.      i0 = i * sy;
  311.      i1 = (i+1) * sy - EPSILON;
  312.      alpha = i*sy - i0;
  313.      for (j=0;j<widthout;j++) {
  314.         j0 = j * sx;
  315.         j1 = (j+1) * sx - EPSILON;
  316.         beta = j*sx - j0;
  317.  
  318.         /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
  319.         src00 = tempin + (i0 * widthin + j0) * components;
  320.         src01 = tempin + (i0 * widthin + j1) * components;
  321.         src10 = tempin + (i1 * widthin + j0) * components;
  322.         src11 = tempin + (i1 * widthin + j1) * components;
  323.  
  324.         dst = tempout + (i * widthout + j) * components;
  325.  
  326.         for (k=0;k<components;k++) {
  327.            s1 = *src00++ * (1.0-beta) + *src01++ * beta;
  328.            s2 = *src10++ * (1.0-beta) + *src11++ * beta;
  329.            *dst++ = s1 * (1.0-alpha) + s2 * alpha;
  330.         }
  331.      }
  332.       }
  333.    }
  334.    else {
  335.       /* shrink width and/or height:  use an unweighted box filter */
  336.       GLint i0, i1;
  337.       GLint j0, j1;
  338.       GLint ii, jj;
  339.       GLfloat sum, *dst;
  340.  
  341.       for (i=0;i<heightout;i++) {
  342.      i0 = i * sy;
  343.      i1 = (i+1) * sy - EPSILON;
  344.      for (j=0;j<widthout;j++) {
  345.         j0 = j * sx;
  346.         j1 = (j+1) * sx - EPSILON;
  347.  
  348.         dst = tempout + (i * widthout + j) * components;
  349.  
  350.         /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
  351.         for (k=0;k<components;k++) {
  352.            sum = 0.0;
  353.            for (ii=i0;ii<=i1;ii++) {
  354.           for (jj=j0;jj<=j1;jj++) {
  355.              sum += *(tempin + (ii * widthin + jj) * components + k);
  356.           }
  357.            }
  358.            sum /= (j1-j0+1) * (i1-i0+1);
  359.            *dst++ = sum;
  360.         }
  361.      }
  362.       }
  363.    }
  364. #endif
  365.  
  366.  
  367.    /*
  368.     * Return output image
  369.     */
  370.  
  371.    if (packrowlength>0) {
  372.       rowlen = packrowlength;
  373.    }
  374.    else {
  375.       rowlen = widthout;
  376.    }
  377.    if (sizeout >= packalignment) {
  378.       rowstride = components * rowlen;
  379.    }
  380.    else {
  381.       rowstride = packalignment/sizeout
  382.             * CEILING( components * rowlen * sizeout, packalignment );
  383.    }
  384.  
  385.    switch (typeout) {
  386.       case GL_UNSIGNED_BYTE:
  387.      k = 0;
  388.      for (i=0;i<heightout;i++) {
  389.         GLubyte *ubptr = (GLubyte *) dataout
  390.                        + i * rowstride
  391.                + packskiprows * rowstride
  392.                + packskippixels * components;
  393.         for (j=0;j<widthout*components;j++) {
  394.                dummy(j, k+i);
  395.            *ubptr++ = (GLubyte) tempout[k++];
  396.         }
  397.      }
  398.      break;
  399.       case GL_BYTE:
  400.      k = 0;
  401.      for (i=0;i<heightout;i++) {
  402.         GLbyte *bptr = (GLbyte *) dataout
  403.                      + i * rowstride
  404.              + packskiprows * rowstride
  405.              + packskippixels * components;
  406.         for (j=0;j<widthout*components;j++) {
  407.                dummy(j, k+i);
  408.            *bptr++ = (GLbyte) tempout[k++];
  409.         }
  410.      }
  411.      break;
  412.       case GL_UNSIGNED_SHORT:
  413.      k = 0;
  414.      for (i=0;i<heightout;i++) {
  415.         GLushort *usptr = (GLushort *) dataout
  416.                         + i * rowstride
  417.                 + packskiprows * rowstride
  418.                 + packskippixels * components;
  419.         for (j=0;j<widthout*components;j++) {
  420.                dummy(j, k+i);
  421.            *usptr++ = (GLushort) tempout[k++];
  422.         }
  423.      }
  424.      break;
  425.       case GL_SHORT:
  426.      k = 0;
  427.      for (i=0;i<heightout;i++) {
  428.         GLshort *sptr = (GLshort *) dataout
  429.                       + i * rowstride
  430.               + packskiprows * rowstride
  431.               + packskippixels * components;
  432.         for (j=0;j<widthout*components;j++) {
  433.                dummy(j, k+i);
  434.            *sptr++ = (GLshort) tempout[k++];
  435.         }
  436.      }
  437.      break;
  438.       case GL_UNSIGNED_INT:
  439.      k = 0;
  440.      for (i=0;i<heightout;i++) {
  441.         GLuint *uiptr = (GLuint *) dataout
  442.                       + i * rowstride
  443.               + packskiprows * rowstride
  444.               + packskippixels * components;
  445.         for (j=0;j<widthout*components;j++) {
  446.                dummy(j, k+i);
  447.            *uiptr++ = (GLuint) tempout[k++];
  448.         }
  449.      }
  450.      break;
  451.       case GL_INT:
  452.      k = 0;
  453.      for (i=0;i<heightout;i++) {
  454.         GLint *iptr = (GLint *) dataout
  455.                     + i * rowstride
  456.             + packskiprows * rowstride
  457.             + packskippixels * components;
  458.         for (j=0;j<widthout*components;j++) {
  459.                dummy(j, k+i);
  460.            *iptr++ = (GLint) tempout[k++];
  461.         }
  462.      }
  463.      break;
  464.       case GL_FLOAT:
  465.      k = 0;
  466.      for (i=0;i<heightout;i++) {
  467.         GLfloat *fptr = (GLfloat *) dataout
  468.                       + i * rowstride
  469.               + packskiprows * rowstride
  470.               + packskippixels * components;
  471.         for (j=0;j<widthout*components;j++) {
  472.                dummy(j, k+i);
  473.            *fptr++ = tempout[k++];
  474.         }
  475.      }
  476.      break;
  477.       default:
  478.      return GLU_INVALID_ENUM;
  479.    }
  480.  
  481.  
  482.    /* free temporary image storage */
  483.    free( tempin );
  484.    free( tempout );
  485.  
  486.    return 0;
  487. }
  488.  
  489.  
  490.  
  491. /*
  492.  * Return the largest k such that 2^k <= n.
  493.  */
  494. static GLint ilog2( GLint n )
  495. {
  496.    GLint k;
  497.  
  498.    if (n<=0) return 0;
  499.    for (k=0; n>>=1; k++) ;
  500.    return k;
  501. }
  502.  
  503.  
  504.  
  505. /*
  506.  * Find the value nearest to n which is also a power of two.
  507.  */
  508. static GLint round2( GLint n )
  509. {
  510.    GLint m;
  511.  
  512.    for (m=1; m<n; m*=2)
  513.      ;
  514.  
  515.    /* m>=n */
  516.    if (m-n <= n-m/2) {
  517.       return m;
  518.    }
  519.    else {
  520.       return m/2;
  521.    }
  522. }
  523.  
  524.  
  525. /*
  526.  * Given an pixel format and datatype, return the number of bytes to
  527.  * store one pixel.
  528.  */
  529. static GLint bytes_per_pixel( GLenum format, GLenum type )
  530. {
  531.    GLint n, m;
  532.  
  533.    switch (format) {
  534.       case GL_COLOR_INDEX:
  535.       case GL_STENCIL_INDEX:
  536.       case GL_DEPTH_COMPONENT:
  537.       case GL_RED:
  538.       case GL_GREEN:
  539.       case GL_BLUE:
  540.       case GL_ALPHA:
  541.       case GL_LUMINANCE:
  542.      n = 1;
  543.      break;
  544.       case GL_LUMINANCE_ALPHA:
  545.      n = 2;
  546.      break;
  547.       case GL_RGB:
  548.      n = 3;
  549.      break;
  550.       case GL_RGBA:
  551.      n = 4;
  552.      break;
  553.       default:
  554.      n = 0;
  555.    }
  556.  
  557.    switch (type) {
  558.       case GL_UNSIGNED_BYTE:    m = sizeof(GLubyte);    break;
  559.       case GL_BYTE:        m = sizeof(GLbyte);    break;
  560.       case GL_BITMAP:        m = 1;            break;
  561.       case GL_UNSIGNED_SHORT:    m = sizeof(GLushort);    break;
  562.       case GL_SHORT:        m = sizeof(GLshort);    break;
  563.       case GL_UNSIGNED_INT:    m = sizeof(GLuint);    break;
  564.       case GL_INT:        m = sizeof(GLint);    break;
  565.       case GL_FLOAT:        m = sizeof(GLfloat);    break;
  566.       default:            m = 0;
  567.    }
  568.  
  569.    return n * m;
  570. }
  571.  
  572.  
  573.  
  574. /*
  575.  * WARNING: This function isn't finished and has never been tested!!!!
  576.  */
  577. __asm __saveds GLint APIENTRY gluBuild1DMipmaps( register __d0 GLenum target, register __d1 GLint components,
  578.                                                  register __d2 GLint width, register __d3 GLenum format,
  579.                                                  register __d4 GLenum type, register __a0 const void *data )
  580. {
  581.    GLubyte *texture;
  582.    GLint levels, max_levels;
  583.    GLint new_width, max_width;
  584.    GLint i, j, k, l;
  585.  
  586.    glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width );
  587.    max_levels = ilog2( max_width ) + 1;
  588.  
  589.    /* Compute how many mipmap images to make */
  590.    levels = ilog2( width ) + 1;
  591.    if (levels>max_levels) {
  592.       levels = max_levels;
  593.    }
  594.  
  595.    new_width = 1 << (levels-1);
  596.  
  597.    texture = (GLubyte *) malloc( new_width * components );
  598.    if (!texture) {
  599.       return GLU_OUT_OF_MEMORY;
  600.    }
  601.  
  602.    if (width != new_width) {
  603.       /* initial rescaling */
  604.       switch (type) {
  605.      case GL_UNSIGNED_BYTE:
  606.         {
  607.            GLubyte *ub_data = (GLubyte *) data;
  608.            for (i=0;i<new_width;i++) {
  609.           j = i * width / new_width;
  610.           for (k=0;k<components;k++) {
  611.              texture[i*components+k] = ub_data[j*components+k];
  612.           }
  613.            }
  614.         }
  615.         break;
  616.      default:
  617.         /* Not implemented */
  618.         return GLU_ERROR;
  619.       }
  620.    }
  621.  
  622.    /* generate and load mipmap images */
  623.    for (l=0;l<levels;l++) {
  624.       glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0,
  625.             format, GL_UNSIGNED_BYTE, texture );
  626.  
  627.       /* Scale image down to 1/2 size */
  628.       new_width = new_width / 2;
  629.       for (i=0;i<new_width;i++) {
  630.      for (k=0;k<components;k++) {
  631.         GLint sample1, sample2;
  632.         sample1 = (GLint) texture[i*2*components+k];
  633.         sample2 = (GLint) texture[(i*2+1)*components+k];
  634.         texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2);
  635.      }
  636.       }
  637.    }
  638.  
  639.    free( texture );
  640.  
  641.    /* make sure remaining mipmap levels are removed */
  642.    for (l=levels;l<max_levels;l++) {
  643.       glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0,
  644.             format, GL_UNSIGNED_BYTE, NULL );
  645.    }
  646.  
  647.    return 0;
  648. }
  649.  
  650.  
  651.  
  652. __asm __saveds GLint APIENTRY gluBuild2DMipmaps( register __d0 GLenum target, register __d1 GLint components,
  653.                                                  register __d2 GLint width, register __d3 GLint height, register __d4 GLenum format,
  654.                                                  register __d5 GLenum type, register __a0 const void *data )
  655. {
  656.    GLint w, h, maxsize;
  657.    void *image, *newimage;
  658.    GLint neww, newh, level, bpp;
  659.    int error;
  660.  
  661.    glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize );
  662.  
  663.    w = round2( width );
  664.    if (w>maxsize) {
  665.       w = maxsize;
  666.    }
  667.    h = round2( height );
  668.    if (h>maxsize) {
  669.       h = maxsize;
  670.    }
  671.  
  672.    bpp = bytes_per_pixel( format, type );
  673.    if (bpp==0) {
  674.       /* probably a bad format or type enum */
  675.       return GLU_INVALID_ENUM;
  676.    }
  677.  
  678.    if (w!=width || h!=height) {
  679.       /* must rescale image to get "top" mipmap texture image */
  680.       image = malloc( (w+4) * h * bpp );
  681.       if (!image) {
  682.      return GLU_OUT_OF_MEMORY;
  683.       }
  684.       error = gluScaleImage( format, width, height, type, data,
  685.                  w, h, type, image );
  686.       if (error) {
  687.      return error;
  688.       }
  689.    }
  690.    else {
  691.       image = (void *) data;
  692.    }
  693.  
  694.    level = 0;
  695.    while (1) {
  696.       glTexImage2D( target, level, components, w, h, 0, format, type, image );
  697.  
  698.       if (w==1 && h==1)  break;
  699.  
  700.       neww = (w<2) ? 1 : w/2;
  701.       newh = (h<2) ? 1 : h/2;
  702.       newimage = malloc( (neww+4) * newh * bpp );
  703.       if (!newimage) {
  704.      return GLU_OUT_OF_MEMORY;
  705.       }
  706.  
  707.       error =  gluScaleImage( format, w, h, type, image,
  708.                   neww, newh, type, newimage );
  709.       if (error) {
  710.      return error;
  711.       }
  712.  
  713.       if (image!=data) {
  714.      free( image );
  715.       }
  716.       image = newimage;
  717.  
  718.       w = neww;
  719.       h = newh;
  720.       level++;
  721.    }
  722.  
  723.    if (image!=data) {
  724.       free( image );
  725.    }
  726.  
  727.    return 0;
  728. }
  729.  
  730.